﻿using System;
using System.Collections.Generic;
using System.Text;
using dAmn;
using llamaServer;
using llAma.Backend.Interface;
using System.Text.RegularExpressions;

namespace llAma.Base
{
    public abstract class llamaCommonBase : IHandlePackets
    {
        protected llamaCommonBase()
        {
        }
        public Packet EmptyRecvPacket { get { return Packet.parse("recv " + GetNamespace() + "\n\n"); } }
        PacketProcessor mPacketProcessor;
        /// <summary>
        /// This function validates that a packet is intended to be handled by this class.
        /// The default implementation returns true at all times, Override to filter packets.
        /// </summary>
        /// <param name="p">Packet in question</param>
        /// <returns>boolean value indicating if the events should be executed for this packet.</returns>
        protected virtual bool PacketPredicate(Packet p)
        {
            return true;
        }
        private bool mUseThread = true;
        protected bool HandleOnSeperateThread
        {
            get { return mUseThread; }
            set { mUseThread = value; }
        }
        //Implement a few things, Like packet handling.
        delegate void pkthandler(Packet p, object sender);
        static DEPool pool = new DEPool();
        public static DelayedExecution GetNewFromPool()
        {
            return pool.GetPump();
        }
        protected void Invoke(Delegate d)
        {
            dePump.Invoke(d);
        }
        protected void Invoke(Delegate d, params object[] args)
        {
            dePump.Invoke(d, args);
        }
        protected bool InvokeRequired
        {
            get { return mUseThread == true && dePump.InvokeRequired; }
        }
        DelayedExecution dePump = GetNewFromPool();
        /// <summary>
        /// This function fires any events in the current class that match the packet passed.
        /// </summary>
        /// <param name="p">Packet for the events that need to be executed.</param>
        /// <param name="sender">Original sender of the event. Pass an existing sender, or in the case the event originates from this class, Pass this instead.</param>
        /// <exception cref="System.InvalidOperationException">Fired when sender or p == null</exception>
        protected void ExecutePacketEvents(Packet p, object sender)
        {
            if (mPacketProcessor == null)
                mPacketProcessor = new PacketProcessor(this);
            if (p == null || sender == null)
                throw new InvalidOperationException("Packet, and sender cannot be null.");
            //Don't process packets for dead connections please.
            if (!((IConnection)sender).Connected)
                return;
            if (dePump.InvokeRequired)
            {
                dePump.Invoke(new pkthandler(ExecutePacketEvents), p, sender);
                return;
            }
            mPacketProcessor.ExecuteMethodsOnCommand(p, sender);
        }
        [Obsolete("Please use packet.ToString(), This function will be removed in the near future.", false)]
        protected string SerializePacket(Packet p)
        {
            return p.ToString();
        }
        protected string SanitizeUserInput(string input)
        {
            return SanitizeUserInput(input, true);
        }
        static string[] regex = { 
                @"&lt;br /&gt;",
                @"&lt;(/?)(b|i|u|s|code|pre|sub|sup)&gt;", 
                @"&lt;(/?)bcode&gt;",
                "&lt;a href=\"([^\"]+)\"&gt;(.*?)&lt;/a&gt;",
                "([^\"]|^)(https?://([^\\ ]+)) \\((.*?)\\)",
                "([^\"]|^)(https?://([^\\ ]+))",
                "&lt;abbr title='(.+?)'&gt;(.*?)&lt/abbr&gt;",
                "&lt;abbr title=\"(.+?)\"&gt;(.*?)&lt/abbr&gt;"
            };
        static string[] repl = {
                @"<br />",
                @"<$1$2>",
                @"<$1pre><$1code>",
                "<a href=\"$1\">$2</a>",
                "$1<a href=\"$2\">$4</a>",
                "$1<a href=\"$2\">[link]</a>",
                "<abbr title='$1'>$2</abbr>",
                "<abbr title='$1'>$2</abbr>"
            };
        protected string SanitizeUserInput(string input, bool parseCodes)
        {

            input = input.TrimEnd('\n').Trim();
            input = input.Replace("&lt;", "&amp;lt;");
            input = input.Replace("&gt;", "&amp;gt;");
            input = input.Replace("<", "&lt;");
            input = input.Replace(">", "&gt;");
            input = input.Replace("\n", "<br />");
            if (parseCodes)
            {
                for (int i = 0; i < regex.Length; i++)
                {
                    input = Regex.Replace(input, regex[i], repl[i], RegexOptions.IgnoreCase);
                }
            }
            return input;
        }
        protected void SendErrorPacketToClient(IConnection conn, Packet p, string e)
        {
            conn.Send(string.Format("{0} {1}\ne={2}\n\n", p.cmd, p.param, e));
        }

        void IHandlePackets.HandlePacket(Packet p, IConnection sender)
        {
            ExecutePacketEvents(p, sender);
        }

        public DateTime FromTS(string ts)
        {
            long t = 0;
            long.TryParse(ts, out t);
            return FromTS(t);
        }
        public DateTime FromTS(long ts)
        {
            DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            return Epoch.AddSeconds(ts).ToLocalTime();
        }
        public long GetTS(DateTime dt)
        {
            DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            TimeSpan ts = dt.ToUniversalTime() - Epoch;
            return Math.Abs((long)ts.TotalSeconds);
        }
        protected abstract string GetNamespace();
    }
}
